package controller.factories;

import java.util.ArrayList;
import java.util.List;

import controller.ModelDummy;
import controller.dispatchers.AbstractDispatcher;
import controller.dispatchers.ModelDispatcher;
import controller.dispatchers.ViewDispatcher;
import controller.listeners.AbstractActionListener;
import controller.listeners.AreaViewActionListener;
import controller.listeners.KeyboardListener;
import controller.listeners.SplashViewActionListener;
import controller.listeners.StatusViewActionListener;

/*
 * This class constructs the Controller from scratch, and ensures
 * that all internal object construction is carried out correctly
 */
public class ControllerBuilder
{
	// Model Reference -- CURRENTLY A DUMMY
	ModelDummy model;
	
	// Event Dispatchers
	AbstractDispatcher modelDispatcher;
	AbstractDispatcher viewDispatcher;
	
	// Listener Factories
	AbstractActionListenerFactory actionListenerFactory;
	KeyboardListenerFactory keyListenerFactory;
	
	// Command Factories
	CommandFactory modelFactory = new ModelCommandFactory();
	CommandFactory viewFactory = new ViewCommandFactory();
	
	// Concrete Listener Factories
	AbstractActionListenerFactory avalFactory = new AreaViewActionListenerFactory();
	AbstractActionListenerFactory spvalFactory = new SplashViewActionListenerFactory();
	AbstractActionListenerFactory stvalFactory = new StatusViewActionListenerFactory();
	KeyboardListenerFactory keyFactory = new KeyboardListenerFactory();
	
	// intance variables
	List<AbstractActionListener> aList; 
	List<KeyboardListener> kList;
	
	// ...And Object said, "Let there be a Controller!"
	public ControllerBuilder(ModelDummy model)
	{
		this.model = model;
		modelDispatcher = new ModelDispatcher(model);
		viewDispatcher = new ViewDispatcher(model);
		System.out.println("[CONTROLLER] " + toString() + " initiated." +
				" Waiting for call to construct()...");
	}
	
	public void contruct()
	{
		// do controller contruction
		System.out.println("[CONTROLLER] Controller construction initiated...");
		System.out.println("[CONTROLLER] Building Listeners... ");
		constructListeners();
		
		// ... more operations ... 
		System.out.println("[CONTROLLER] Controller construction completed!");
	}
	
	// uses the instantiated factories to contstruct appropriate listener
	// objects and worker threads
	private void constructListeners()
	{
		// initiate the action listner set
		aList = new ArrayList<AbstractActionListener>();
		kList = new ArrayList<KeyboardListener>();
		
		// AreaViewActionListener
		setActionListenerFactory(avalFactory);
		System.out.println("[CONTROLLER] Building " + actionListenerFactory.toString() + "... ");
		aList.add(constructActionListener());
		System.out.println("[CONTROLLER] Done!");
		
		// SplashViewActionListener
		setActionListenerFactory(spvalFactory);
		System.out.println("[CONTROLLER] Building " + actionListenerFactory.toString() + "... ");
		aList.add(constructActionListener());
		System.out.println("[CONTROLLER] Done!");
		
		// StatusViewActionListener
		setActionListenerFactory(stvalFactory);
		System.out.println("[CONTROLLER] Building " + actionListenerFactory.toString() + "... ");
		aList.add(constructActionListener());
		System.out.println("[CONTROLLER] Done!");
		
		// KeyboardListener
		setKeyListenerFactory(keyFactory);
		System.out.println("[CONTROLLER] Building " + keyListenerFactory.toString() + "... ");
		kList.add(constructKeyListener());
		System.out.println("[CONTROLLER] Done!");
		
		// ...potentially more listeners...
		System.out.println("[CONTROLLER] Listener contruction completed!");
	}
	
	private AbstractActionListener constructActionListener()
	{
		return actionListenerFactory.createAbstractActionListener();
	}
	
	private KeyboardListener constructKeyListener()
	{
		return keyListenerFactory.createKeyboardListner();
	}
	
	// setter for action listener factory
	private void setActionListenerFactory( AbstractActionListenerFactory aalf )
	{
		this.actionListenerFactory = aalf;
	}
	
	// setter for key listener factory
	private void setKeyListenerFactory( KeyboardListenerFactory klf )
	{
		this.keyListenerFactory = klf;
	}
	
	/*
	 * ------------------------
	 * *** PUBLIC INTERFACE *** 
	 * ------------------------
	 */
	public AbstractDispatcher getModelDispatcher()
	{
		return modelDispatcher;
	}

	public AbstractDispatcher getViewDispatcher()
	{
		return viewDispatcher;
	}

	public List<AbstractActionListener> getAList()
	{
		return aList;
	}

	public List<KeyboardListener> getKList()
	{
		return kList;
	}
	
	public String toString()
	{
		return "ControllerBuilder";
	}
	
	/*
	 * -------------------------
	 * *** PRIVATE FACTORIES ***
	 * -------------------------
	 */
	
	// Returns new AreaViewActionListeners
	private class AreaViewActionListenerFactory extends AbstractActionListenerFactory
	{
		@Override // factory method
		public AbstractActionListener createAbstractActionListener()
		{
			return new AreaViewActionListener(modelDispatcher, viewDispatcher, modelFactory, viewFactory);
		}
		
		public String toString()
		{
			return getClass().getSimpleName();
		}
	}
	
	// Returns new SplashViewActionListeners
	private class SplashViewActionListenerFactory extends AbstractActionListenerFactory
	{
		@Override // factory method
		public AbstractActionListener createAbstractActionListener()
		{
			return new SplashViewActionListener(modelDispatcher, viewDispatcher, modelFactory, viewFactory);
		}
		
		public String toString()
		{
			return getClass().getSimpleName();
		}
	}
	
	// Returns new StatusViewActionListeners
	private class StatusViewActionListenerFactory extends AbstractActionListenerFactory
	{
		@Override // factory method
		public AbstractActionListener createAbstractActionListener()
		{
			return new StatusViewActionListener(modelDispatcher, viewDispatcher, modelFactory, viewFactory);
		}
		
		public String toString()
		{
			return getClass().getSimpleName();
		}
	}
	
	// Returns new KeyboardListeners
	public class KeyboardListenerFactory
	{
		// factory method
		public KeyboardListener createKeyboardListner()
		{
			return new KeyboardListener(modelDispatcher, viewDispatcher, modelFactory, viewFactory);
		}
		
		public String toString()
		{
			return getClass().getSimpleName();
		}
	}
}
